import type { Canvas } from 'canvaskit-wasm'
import { DateTime } from 'luxon'
import { ChartLayout } from './chartLayout'
import type { BaseChartOptions, BaseChartStyle } from './baseChart'
import { BaseChart } from './baseChart'
import type { BaseSimpleChart } from './baseSimpleChart'

/**
 * MixedChart options.
 * @public
 * @interface
 * @category MixedChart
 * @extends BaseChartOptions
 */
export interface MixedChartOptions extends BaseChartOptions {
}

/**
 * MixedChart style.
 * @public
 * @interface
 * @category MixedChart
 * @extends BaseChartStyle
 */
export interface MixedChartStyle extends BaseChartStyle {
}

/**
 * ChartSet in MixedChart.
 * @public
 * @interface
 * @category MixedChart
 * @template T - The type of the chart. Should be a subclass of BaseSimpleChart.
 */
export interface ChartSet<T extends typeof BaseSimpleChart> {
  /**
   * The type of the chart.
   */
  Chart: T
  /**
   * The data of the chart.
   */
  data: ConstructorParameters<T>[0]
  /**
   * The options of the chart.
   */
  options?: ConstructorParameters<T>[1]
}

/**
 * MixedChart.
 * @public
 * @category MixedChart
 * @template T - The type of the chart. Should be a subclass of BaseSimpleChart.
 * @extends BaseChart
 * @description
 * MixedChart is a chart that contains multi-type charts. MixedChart will create a layout first, then create the charts in the layout.
 */
export class MixedChart<T extends typeof BaseSimpleChart> extends BaseChart {
  /**
   * The style of the MixedChart.
   * @public
   * @type MixedChartStyle
   */
  declare style: MixedChartStyle

  /**
   * The layout of the MixedChart, which will be generated by the data of the charts.
   * @public
   * @type ChartLayout
   */
  layout: ChartLayout
  /**
   * The charts in the MixedChart.
   */
  charts: BaseSimpleChart[]

  /**
   * Create a MixedChart.
   * @public
   * @constructor
   * @param chartSet - The chart set of the MixedChart.
   * @param options - The options of the MixedChart.
   */
  constructor(
    chartSet: ChartSet<T>[],
    options?: MixedChartOptions,
  ) {
    options ??= {}
    super(options)
    const data = {
      labels: chartSet[0].data.labels,
      datasets: chartSet.flatMap(set => (set.data.datasets)),
    }
    const setOptions: ConstructorParameters<T>[1] = {}
    chartSet.flatMap(set => (set.options)).forEach((option) => {
      for (const key in option)
        setOptions[key] = option[key]
    })

    chartSet.forEach((set) => {
      set.data.datasets.forEach((dataset) => {
        dataset.data.forEach((dataUnit, index) => {
          if (!(!dataUnit.isIndexDate() && dataUnit.index) && set.data.labels && set.data.labels[index] instanceof DateTime)
            dataUnit.index = <DateTime> set.data.labels[index]
        })
      })
    })

    this.layout = new ChartLayout(data, {
      gridAlign: true,
      edgeOffset: !(options.gridAlign ?? setOptions.gridAlign ?? true), // endColumn: false -> beginOffset: true
      ...setOptions,
      ...options,
      x: 0,
      y: 0,
    })

    chartSet.forEach((set) => {
      set.data.datasets.forEach((dataset) => {
        dataset.data.forEach((dataUnit, index) => {
          if (!(!dataUnit.isIndexDate() && dataUnit.index) && set.data.labels && typeof set.data.labels[index] === 'string')
            dataUnit.index = this.layout.index.pos[index]
        })
      })
    })

    this.charts = chartSet.map(set => new set.Chart(set.data, {
      ...options,
      x: 0,
      y: 0,
      ...set.options,
      layout: this.layout,
    }))
    this.add(this.layout, ...this.charts)
  }

  draw(_canvas: Canvas) {
    super.draw(_canvas)
    this.layout.progress = this.progress
    this.charts.forEach(chart => chart.progress = this.progress)
  }
}
